home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 …ember: Reference Library / Dev.CD Dec 00 RL Disk 1.toast / pc / technical documentation / develop / develop issue 26 / develop issue 26 code / truffles - display mgr. / sprocket / sources / window.cp < prev   
Encoding:
Text File  |  1996-06-05  |  25.6 KB  |  1,081 lines

  1. /*
  2.     File:        Window.cp
  3.  
  4.     Contains:    Implementation of TWindow, a base class which provides a
  5.                 framework for building way-cool windows which even John
  6.                 Sullivan would be happy with. Floating windows and “smart
  7.                 zooming” algorithms are based on code samples provided by
  8.                 Dean Yu. Tim Craycroft, the guy making the window manager
  9.                 do all this work for you has also been a great help.
  10.                 
  11.     Written by: Dave Falkenburg
  12.  
  13.     Copyright:    © 1993-1995 by Dave Falkenburg, all rights reserved.
  14.  
  15.     Change History (most recent first):
  16.     
  17.         <14>     1/24/95    DRF        DoMenuSelection now returns a Boolean. Added some default
  18.                                     behavior for handling the close menu item-- this will change
  19.                                     when we make some things recordable.
  20.         <13>     1/20/95    DRF        Fix the “calling DisposeWindow on DialogPtr” problem reported by
  21.                                     Gary Powell @ Adobe by adding a cheezy flag that TWindow
  22.                                     initializes, but TDialogWindow slams. In TWindow::Close, we
  23.                                     check this flag and call DisposeDialog instead of DisposeWindow,
  24.                                     surely preventing memory leaks for complex dialogs.
  25.         <12>      1/3/95    DRF        Add Nitin’s changes for Drag handling: a ClickAndDrag method.
  26.         <11>      1/3/95    DRF        DoMenuCommand now returns a Boolean. Also got rid of
  27.                                     conditionals for ClipAbove: by the time this gets to print
  28.                                     everyone should be using Universal Headers 2.0.
  29.         <10>     12/6/94    DRF        Rolled in David Den Boer’s fixes. Also add the conditionals for
  30.                                     newest universal headers again.
  31.          <9>    11/23/94    DRF        Bite the bullet just require the latest universal headers
  32.          <8>    11/17/94    DRF        Add casts for CFront & PPCC. Also dealt with the change to
  33.                                     ClipAbove in the latest universal headers.
  34.          <7>    11/12/94    DRF        Added AdjustMenusBeforeMenuSelection.
  35.          <6>     11/8/94    DRF        Add some better menu handling methods.
  36.          <5>     9/27/94    DRF         AppLib.h is now Sprocket.h
  37.          <4>      9/9/94    DRF        Reorganized headers and removed redundant #includes.
  38.          <3>      9/4/94    DRF        Added DrawJustTheGrowIcon.
  39.          <2>     8/27/94    DRF        In TWindow::Close, call window’s (de)Activate method before
  40.                                     closing so that menus can be properly updated.
  41.     
  42.     To Do:        Make sure invisible windows can be created & managed
  43.                 Handle modal windows as another class of windows
  44.                 Fix activate bugs when showing and hiding windows
  45.                 Window positioning methods (getters and setters)
  46.                 Display Manager support
  47.                 Changes to support AEObject model
  48.  */
  49.  
  50. #include "Sprocket.h"
  51. #include "Window.h"
  52. #include "UtilityClasses.h"
  53.  
  54. #include <Script.h>        //    for GetMBarHeight()
  55. #include <LowMem.h>        //    for LMGetWindowList()
  56.  
  57.  
  58. UInt32                TWindow::fgModalState = 0;
  59.  
  60.  
  61. const WindowRef     kNoFloatingWindows        = (WindowRef) -1;
  62. const WindowRef        kNoModalWindows            = (WindowRef) -1;
  63.  
  64. const short            kScreenEdgeSlop            = 4;
  65. const short            kSpaceForFinderIcons    = 64;
  66. const short            kMinimumTitleBarHeight    = 21;
  67. const short            kMinimumWindowSize        = 32;
  68.  
  69.  
  70. static void            HiliteShowHideFloatingWindows(Boolean hiliting,Boolean hiding);
  71.  
  72. static pascal void    CalculateWindowAreaOnDevice(short depth,short deviceFlags,GDHandle targetDevice,long userData);
  73.  
  74. struct    CalcWindowAreaDeviceLoopUserData
  75.     {
  76.     GDHandle    fScreenWithLargestPartOfWindow;
  77.     long        fLargestArea;
  78.     Rect        fWindowBounds;
  79.     };
  80.  
  81.  
  82.  
  83. TWindow::TWindow()
  84.     {
  85.     fIsDialogWindow = false;
  86.     }
  87.  
  88.  
  89. TWindow::~TWindow()
  90.     {
  91.     WindowRef    newFrontWindow = NULL;
  92.  
  93.     if (fWindow)
  94.         {
  95.         if (FrontNormalWindow() == fWindow)
  96.             newFrontWindow = GetNextWindow(fWindow);
  97.         
  98.         this->Activate(false);
  99.  
  100.         if (fIsDialogWindow)
  101.             DisposeDialog((DialogRef) fWindow);
  102.         else
  103.             DisposeWindow(fWindow);
  104.  
  105.         if (fWindowType == kModalWindow)
  106.             this->ExitModalState();
  107.         
  108.         if (newFrontWindow)
  109.             HiliteAndActivateWindow(newFrontWindow,true);
  110.         }
  111.     }
  112.  
  113.  
  114.  
  115. void
  116. TWindow::CreateWindow(WindowType typeOfWindowToCreate /* = kNormalWindow */)
  117.     {
  118.     WindowRef    behindWindow;
  119.     WindowRef    oldTopWindow = NULL;
  120.  
  121.     if (typeOfWindowToCreate == kNormalWindow)
  122.         {
  123.         //    normal windows are always created behind modal and floaters
  124.         
  125.         behindWindow = LastFloatingWindow();
  126.         oldTopWindow = FrontNormalWindow();
  127.         }
  128.     else if (typeOfWindowToCreate == kFloatingWindow)
  129.         {
  130.         //    always create floaters behind modal windows
  131.  
  132.         behindWindow = LastModalWindow();
  133.         oldTopWindow = FrontFloatingWindow();
  134.         }
  135.     else if (typeOfWindowToCreate == kModalWindow)
  136.         {
  137.         //    modal windows are always created frontmost
  138.  
  139.         behindWindow = (WindowRef) -1;
  140.         oldTopWindow = FrontModalWindow();
  141.  
  142.         this->EnterModalState();
  143.         }
  144.  
  145.  
  146.     fWindow = this->MakeNewWindow(behindWindow);
  147.  
  148.  
  149.     if (fWindow != NULL)
  150.         {
  151.         SetWRefCon(fWindow,(long) this);
  152.         fIsVisible = IsWindowVisible ( fWindow );
  153.         fWindowType = typeOfWindowToCreate;
  154.         SetWindowKind(fWindow,typeOfWindowToCreate);
  155.  
  156.         if ((fIsVisible) && (fgModalState == 0))
  157.             {
  158.             if (fWindowType == kNormalWindow)
  159.                 HiliteAndActivateWindow(oldTopWindow,false);
  160.  
  161.             else if (fWindowType == kFloatingWindow)
  162.                 HiliteAndActivateWindow(oldTopWindow,true);
  163.  
  164.             HiliteAndActivateWindow(fWindow,true);
  165.             }
  166.         }
  167.     else
  168.         {
  169.         if (fWindowType == kModalWindow)
  170.             this->ExitModalState();
  171.         }
  172.     }
  173.  
  174.  
  175. void
  176. TWindow::AdjustCursor(EventRecord * /* anEvent */)
  177.     {
  178.     }
  179.  
  180.  
  181. void
  182. TWindow::Idle(EventRecord * /* anEvent */)
  183.     {
  184.     }
  185.     
  186. void
  187. TWindow::Activate(Boolean /* activating */)
  188.     {
  189.     }
  190.     
  191. void
  192. TWindow::Draw(void)
  193.     {
  194.     }
  195.     
  196. void
  197. TWindow::Click(EventRecord * /* anEvent */)
  198.     {
  199.     }
  200.     
  201. void
  202. TWindow::KeyDown(EventRecord * /* anEvent */)
  203.     {
  204.     }
  205.  
  206.  
  207. void
  208. TWindow::Select(void)
  209.     {
  210.     WindowRef    oldTopWindow, behindWindow;
  211.     
  212.     if (fWindowType == kNormalWindow)
  213.         {
  214.         oldTopWindow = FrontNormalWindow();
  215.         behindWindow = LastFloatingWindow();
  216.         if (behindWindow == kNoFloatingWindows)
  217.             behindWindow = LastModalWindow();
  218.         }
  219.     else if (fWindowType == kFloatingWindow)
  220.         {
  221.         oldTopWindow = FrontFloatingWindow();
  222.         behindWindow = LastModalWindow();
  223.         }
  224.     else if (fWindowType == kModalWindow)
  225.         {
  226.         oldTopWindow = FrontModalWindow();
  227.         behindWindow = (WindowRef) -1;
  228.         }
  229.     
  230.     if (fWindow != oldTopWindow)
  231.         {
  232.         if (behindWindow == (WindowRef) -1)
  233.             SelectWindow(fWindow);
  234.         else
  235.             SendBehind(fWindow,behindWindow);
  236.  
  237.         if (oldTopWindow != NULL)
  238.             {
  239.             if (fWindowType == kFloatingWindow)
  240.                 HiliteWindow(oldTopWindow,true);
  241.             else
  242.                 HiliteAndActivateWindow(oldTopWindow,false);
  243.             }
  244.  
  245.         HiliteAndActivateWindow(fWindow,true);
  246.         }
  247.     }
  248.  
  249.  
  250. void
  251. TWindow::Drag(Point startPoint)
  252.     {
  253.     GrafPtr        savePort;
  254.     KeyMap        theKeyMap;
  255.     Boolean        commandKeyDown = false;
  256.     long        dragResult;
  257.     
  258.     if (WaitMouseUp())        //    de-bounce?
  259.         {
  260.         // Set up the Window Manager port.
  261.     
  262.         GetPort(&savePort);
  263.         SetPort(gWindowManagerPort);
  264.         SetClip(GetGrayRgn());
  265.  
  266.         // Check to see if the command key is down.
  267.     
  268.         GetKeys(theKeyMap);
  269.         commandKeyDown = ((theKeyMap[1] & 0x8000) != 0);
  270.         
  271.         if (commandKeyDown)
  272.             {
  273.             //    We’re not going to change window ordering,
  274.             //    so make sure that we don’t drag in front of
  275.             //    other windows which may be in front of ours.
  276.  
  277.             ClipAbove(fWindow);
  278.             }
  279.         else if (fWindowType != kFloatingWindow)
  280.             {
  281.             //    We’re dragging a normal window, so make sure
  282.             //    that we don’t drag in front of any floating
  283.             //    windows.
  284.  
  285.             ClipAbove(FrontNormalWindow());
  286.             }
  287.  
  288.         //    Drag an outline of the window around the desktop.
  289.         //    NOTE: DragGrayRgn destroys the region passed in, so make a copy
  290.  
  291.         RgnHandle    tempRgn = NewRgn();
  292.  
  293.         GetWindowStructureRgn(fWindow, tempRgn);
  294.         dragResult = DragGrayRgn(tempRgn, startPoint, &gDeskRectangle, &gDeskRectangle, noConstraint, nil);
  295.  
  296.         DisposeRgn(tempRgn);    
  297.  
  298.         SetPort(savePort);    //    Get back to old port
  299.  
  300.         if ((dragResult != 0) && (dragResult != 0x80008000))
  301.             this->Nudge((short) (dragResult & 0xFFFF),(short) (dragResult >> 16));
  302.         }
  303.  
  304.     if (!commandKeyDown)
  305.         this->Select();
  306.     }
  307.  
  308.  
  309. void
  310. TWindow::Nudge(short horizontalDistance, short verticalDistance)
  311.     {
  312.     short        newHorizontalPosition, newVerticalPosition;
  313.     RgnHandle    tempRgn = NewRgn ();
  314.  
  315.     GetWindowContentRgn ( fWindow, tempRgn );
  316.     newHorizontalPosition = (short) (**tempRgn).rgnBBox.left + horizontalDistance;
  317.     newVerticalPosition   = (short) (**tempRgn).rgnBBox.top  + verticalDistance;
  318.     DisposeRgn ( tempRgn );
  319.  
  320.     MoveWindow(fWindow,newHorizontalPosition,newVerticalPosition,false);
  321.     }
  322.  
  323.  
  324. void
  325. TWindow::Grow(Point startPoint)
  326.     {
  327.     GrafPtr    oldPort;
  328.     long    newSize;
  329.     Rect    oldWindowRect,resizeLimits;
  330.     
  331.     GetPort(&oldPort);
  332.     
  333.     GetWindowSizeLimits(&resizeLimits);
  334.     newSize = GrowWindow(fWindow,startPoint,&resizeLimits);
  335.     if (newSize)
  336.         {
  337.         oldWindowRect = GetWindowPort ( fWindow )->portRect;
  338.         SizeWindow ( fWindow, (short) newSize, (short) (newSize >> 16), true );
  339.         SetPortWindowPort ( fWindow );
  340.         resizeLimits = GetWindowPort ( fWindow )->portRect;
  341.         this->AdjustForNewWindowSize(&oldWindowRect,&resizeLimits);
  342.         }
  343.     
  344.     SetPort(oldPort);
  345.     }
  346.  
  347.  
  348. void
  349. TWindow::Zoom(short zoomState)
  350.     {
  351.     GrafPtr        oldPort;
  352.     FontInfo    systemFontInfo;
  353.     short        titleBarHeight;
  354.     Rect        bestScreenRect,perfectWindowRect,scratchRect;
  355.     short        amountOffscreen;
  356. //    WindowPeek    windowAsWindowPeek = (WindowPeek) fWindow;
  357.     GDHandle    bestDevice;
  358.     
  359.     GetPort(&oldPort);
  360.  
  361.     //    Figure out the height of the title bar so we can properly position
  362.     //    a window. The algorithm is stolen from the System 7.x 'WDEF' (0)
  363.     //
  364.     //    This probably isn’t the best thing to do: A better way might be 
  365.     //    to diff the structure and content region rectangles?
  366.  
  367.     SetPort(gWindowManagerPort);
  368.     GetFontInfo(&systemFontInfo);
  369.     titleBarHeight = (short) (systemFontInfo.ascent + systemFontInfo.descent + 4);
  370.     if ((titleBarHeight % 2) == 1)
  371.         titleBarHeight--;
  372.     if (titleBarHeight < kMinimumTitleBarHeight)
  373.         titleBarHeight = kMinimumTitleBarHeight;
  374.  
  375.  
  376.     //    Only do the voodoo magic if we are really “zooming” the window.
  377.  
  378.     if (zoomState == inZoomOut)
  379.         {
  380.         FindScreenRectWithLargestPartOfWindow(fWindow,&bestScreenRect,&bestDevice);
  381.         bestScreenRect.top += titleBarHeight;
  382.  
  383.         this->GetPerfectWindowSize(&perfectWindowRect);
  384.         OffsetRect(&perfectWindowRect,-perfectWindowRect.left,-perfectWindowRect.top);
  385.  
  386.         //    Take the zero-pined perfect window size and move it to
  387.         //    the top left of the    window’s content region.
  388.  
  389.         RgnHandle    tempRgn = NewRgn ();
  390.         GetWindowContentRgn ( fWindow, tempRgn );
  391.         OffsetRect ( &perfectWindowRect,
  392.                             (**tempRgn).rgnBBox.left, (**tempRgn).rgnBBox.top );
  393.         DisposeRgn ( tempRgn );
  394.  
  395.  
  396.         //    Does perfectWindowRect fit completely on the best screen?
  397.         
  398.         SectRect(&perfectWindowRect, &bestScreenRect, &scratchRect);
  399.         if (!EqualRect(&perfectWindowRect, &scratchRect))
  400.             {
  401.             //    SectRect sez perfectWindowRect doesn’t completely fit
  402.             //    on the screen, so bump the window so that more of it fits.
  403.  
  404.             //    Make sure that the left edge of perfectWindowRect is forced
  405.             //    onto the best screen.  This is in case we are bumping
  406.             //    the window to the right.
  407.  
  408.             amountOffscreen = bestScreenRect.left - perfectWindowRect.left;
  409.             if (amountOffscreen > 0)
  410.                 {
  411.                 perfectWindowRect.left += amountOffscreen;
  412.                 perfectWindowRect.right += amountOffscreen;
  413.                 }
  414.  
  415.             //    Make sure that the left edge of perfectWindowRect is forced
  416.             //    onto the best screen.  This is in case we are bumping
  417.             //    the window downward to a new screen.
  418.     
  419.             amountOffscreen = bestScreenRect.top - perfectWindowRect.top;
  420.             if (amountOffscreen > 0)
  421.                 {
  422.                 perfectWindowRect.top += amountOffscreen;
  423.                 perfectWindowRect.bottom += amountOffscreen;
  424.                 }
  425.  
  426.             //    If right edge of window falls off the screen,
  427.             //        Move window to the left until the right edge IS on the screen
  428.             //        OR the left edge is at bestScreenRect.left
  429.  
  430.             amountOffscreen = perfectWindowRect.right - bestScreenRect.right;
  431.             if (amountOffscreen > 0)
  432.                 {
  433.                 //    Are we going to push the left edge offscreen? If so, change the
  434.                 //    offset so we move the window all the way over to the left.
  435.                 
  436.                 if ((perfectWindowRect.left - amountOffscreen) < bestScreenRect.left)
  437.                     amountOffscreen = perfectWindowRect.left - bestScreenRect.left;
  438.  
  439.                 perfectWindowRect.left -= amountOffscreen;
  440.                 perfectWindowRect.right -= amountOffscreen;
  441.                 }
  442.  
  443.             //    If bottom edge of window falls off the screen,
  444.             //        Move window to up until the bottom edge IS on the screen
  445.             //        OR the top edge is at bestScreenRect.top
  446.  
  447.             amountOffscreen = perfectWindowRect.bottom - bestScreenRect.bottom;
  448.             if (amountOffscreen > 0)
  449.                 {
  450.                 //    Are we going to push the top edge offscreen? If so, change the
  451.                 //    offset so we move the window just to the top.
  452.                 
  453.                 if ((perfectWindowRect.top - amountOffscreen) < bestScreenRect.top)
  454.                     amountOffscreen = perfectWindowRect.top - bestScreenRect.top;
  455.  
  456.                 perfectWindowRect.top -= amountOffscreen;
  457.                 perfectWindowRect.bottom -= amountOffscreen;
  458.                 }
  459.  
  460.             SectRect(&perfectWindowRect, &bestScreenRect, &scratchRect);
  461.             if (!EqualRect(&perfectWindowRect, &scratchRect))
  462.                 {
  463.                 //    The edges of the window still fall offscreen,
  464.                 //    so make the window smaller until it fits.
  465.                 
  466.                 if (perfectWindowRect.bottom > bestScreenRect.bottom)
  467.                     perfectWindowRect.bottom = bestScreenRect.bottom;
  468.  
  469.                 //    If the right edge is still falling off,
  470.                 //        save space for Finder’s disk icons as well.
  471.  
  472.                 if (perfectWindowRect.right > bestScreenRect.right)
  473.                     {
  474.                     perfectWindowRect.right = bestScreenRect.right;
  475.                     
  476.                     //    If we were on the main screen, leave room for Finder icons, too.
  477.                     
  478.                     if (bestDevice == GetMainDevice())
  479.                         perfectWindowRect.right -= kSpaceForFinderIcons;
  480.                     }
  481.                 }
  482.             }
  483.  
  484.         //    Stash our new rectangle inside of the Window’s dataHandle
  485.         //    so that ZoomWindow does the right thing.
  486.         
  487.     //    (**((WStateDataHandle) (windowAsWindowPeek->dataHandle))).stdState = perfectWindowRect;
  488.         SetWindowStandardState ( fWindow, &perfectWindowRect );
  489.         }
  490.  
  491.     //    HEY YOU! Don’t forget to set the port to the window being zoomed
  492.     //    Why, you ask? Because IM-IV-50 says to; otherwise you die
  493.     
  494.     SetPortWindowPort ( fWindow );
  495.  
  496.     Rect    oldWindowRect = GetWindowPort ( fWindow )->portRect;    
  497.     ZoomWindow(fWindow,zoomState,false);
  498.     Rect    newWindowRect = GetWindowPort ( fWindow )->portRect;
  499.     this->AdjustForNewWindowSize(&oldWindowRect,&newWindowRect);
  500.  
  501.     SetPort(oldPort);
  502.     }
  503.  
  504. void
  505. TWindow::ShowHide(Boolean showFlag)
  506.     {
  507.     //    Here we need the “::” in front of ShowHide to indicate we are calling
  508.     //    the global function, and not the method ShowHide. Unintended recursion
  509.     //    can do bad things to the unsuspecting programmer.
  510.     
  511.     //    Some C++ programmers would always prepend the “::” on function calls.
  512.     
  513.     ::ShowHide(fWindow,showFlag);
  514.     fIsVisible = showFlag;
  515.     }
  516.     
  517.  
  518. Boolean
  519. TWindow::EventFilter(EventRecord * /* theEvent */)
  520.     {
  521.     return false;
  522.     }
  523.     
  524.  
  525. void
  526. TWindow::GetPerfectWindowSize(Rect *perfectSize)
  527.     {
  528.     *perfectSize = qd.screenBits.bounds;
  529.     }
  530.  
  531.  
  532. void
  533. TWindow::GetWindowSizeLimits(Rect *limits)
  534.     {
  535.     limits->top = limits->left = kMinimumWindowSize;
  536.     limits->right = gDeskRectangle.right - gDeskRectangle.left;
  537.     limits->bottom = gDeskRectangle.bottom - gDeskRectangle.top;
  538.     }
  539.  
  540.  
  541. void
  542. TWindow::AdjustForNewWindowSize(Rect * /* oldRect */, Rect * /* newSize */)
  543.     {
  544.     }
  545.  
  546.  
  547. Boolean
  548. TWindow::IsVisible(void)
  549.     {
  550.     return fIsVisible;
  551.     }
  552.  
  553.  
  554. Boolean
  555. TWindow::CanClose(void)
  556.     {
  557.     return true;
  558.     }
  559.  
  560.  
  561. Boolean
  562. TWindow::Close(void)
  563.     {
  564.     delete this;
  565.     return true;
  566.     }
  567.  
  568.  
  569. void
  570. TWindow::AdjustMenusBeforeMenuSelection(void)
  571.     {
  572.     }
  573.  
  574.  
  575. void
  576. TWindow::AdjustMenusAfterMenuSelection(void)
  577.     {
  578.     }
  579.  
  580.  
  581. Boolean
  582. TWindow::DoMenuSelection(short /* menu */, short /* item */)
  583.     {
  584.     return false;
  585.     }
  586.     
  587.  
  588. Boolean
  589. TWindow::DoMenuCommand(unsigned long menuCommand)
  590.     {
  591.     if (menuCommand == cClose)
  592.         {
  593.         if (this->CanClose())
  594.             return this->Close();
  595.         }
  596.  
  597.     return false;
  598.     }
  599.  
  600.  
  601. ///////////////////////////////////////////////////////////////////////////
  602. //
  603. //    Drag Manager callback routines which dispatch to a window’s method
  604. //
  605.  
  606. /* static */ pascal OSErr
  607. TWindow::CallDragTrackingHandler(DragTrackingMessage dragMessage,WindowRef theWindow,void * /* refCon */,DragReference theDrag)
  608.     {
  609.     TWindow *wobj = GetWindowObject(theWindow);
  610.     
  611.     if (wobj)
  612.         return(wobj->HandleDrag(dragMessage,theDrag));
  613.     else
  614.         return dragNotAcceptedErr;
  615.     }
  616.  
  617.     
  618. /* static */ pascal OSErr
  619. TWindow::CallDragReceiveHandler(WindowRef theWindow,void * /* refCon */,DragReference theDrag)
  620.     {
  621.     TWindow *wobj = GetWindowObject(theWindow);
  622.     
  623.     if (wobj)
  624.         return(wobj->HandleDrop(theDrag));
  625.     else
  626.         return dragNotAcceptedErr;
  627.     }
  628.  
  629.  
  630. OSErr
  631. TWindow::HandleDrag(DragTrackingMessage dragMessage,DragReference theDrag)
  632.     {
  633.     OSErr    result = dragNotAcceptedErr;
  634.     
  635.     switch (dragMessage)
  636.         {
  637.         case    dragTrackingEnterWindow:
  638.             result = this->DragEnterWindow(theDrag);
  639.             break;
  640.         
  641.         case    dragTrackingInWindow:
  642.             result = this->DragInWindow(theDrag);
  643.             break;
  644.             
  645.         case    dragTrackingLeaveWindow:
  646.             result = this->DragLeaveWindow(theDrag);
  647.             break;
  648.             
  649.         default:
  650.             break;
  651.         }
  652.  
  653.     return result;
  654.     }
  655.     
  656.  
  657. OSErr
  658. TWindow::HandleDrop(DragReference /* theDrag */)
  659.     {
  660.     return dragNotAcceptedErr;
  661.     }
  662.  
  663.  
  664. OSErr
  665. TWindow::DragEnterWindow(DragReference /* theDrag */)
  666.     {
  667.     return dragNotAcceptedErr;
  668.     }
  669.  
  670.  
  671. OSErr
  672. TWindow::DragInWindow(DragReference /* theDrag */)
  673.     {
  674.     return dragNotAcceptedErr;
  675.     }
  676.  
  677.  
  678. OSErr
  679. TWindow::DragLeaveWindow(DragReference /* theDrag */)
  680.     {
  681.     return dragNotAcceptedErr;
  682.     }
  683.  
  684.  
  685. Boolean
  686. TWindow::IsPointInContentRgn( Point pt )
  687.     {
  688.     RgnHandle    tempRgn = NewRgn();
  689.  
  690.     GetWindowContentRgn(fWindow, tempRgn);
  691.     Boolean result = PtInRgn( pt, tempRgn );
  692.  
  693.     DisposeRgn(tempRgn);
  694.  
  695.     return result;
  696.     }
  697.  
  698.  
  699. Boolean
  700. TWindow::IsDragInContentRgn( DragReference dragRef )
  701.     {
  702.     Point    globalMouse;
  703.     OSErr    err;
  704.     
  705.     err = GetDragMouse( dragRef, &globalMouse, 0L );
  706.     
  707.     if ( err == noErr )
  708.         return( this->IsPointInContentRgn( globalMouse ) );
  709.     else
  710.         return( false );
  711.     }
  712.  
  713.  
  714. Rect
  715. TWindow::GetContentsBounds(void)
  716.     {
  717.     RgnHandle    tempRgn = NewRgn();
  718.     Rect        r;
  719.  
  720.     GetWindowContentRgn(fWindow, tempRgn);
  721.     r = (**tempRgn).rgnBBox;
  722.  
  723.     DisposeRgn(tempRgn);
  724.     return r;
  725.     }
  726.  
  727.  
  728. DeviceLoopDrawingUPP CallCalcWindowAreaOnDevice = NewDeviceLoopDrawingProc(&CalculateWindowAreaOnDevice);
  729.  
  730. void
  731. TWindow::FindScreenRectWithLargestPartOfWindow(WindowRef aWindow,Rect *theBestScreenRect,GDHandle * theBestDevice)
  732.     {
  733.     RgnHandle                            copyOfWindowStrucRgn;
  734.     CalcWindowAreaDeviceLoopUserData    deviceLoopData;
  735.  
  736.     //    Use DeviceLoop to find out what GDevice contains the largest
  737.     //    portion of the supplied window.
  738.     //
  739.     //    NOTE:    Assumes thePort == the Window Manager Port because we using
  740.     //            the window strucRgn, not contRgn.
  741.  
  742.     deviceLoopData.fScreenWithLargestPartOfWindow = nil;
  743.     deviceLoopData.fLargestArea = -1;
  744.  
  745.     RgnHandle    tempRgn = NewRgn ();
  746.     GetWindowContentRgn ( aWindow, tempRgn );
  747.     deviceLoopData.fWindowBounds = (**tempRgn).rgnBBox;
  748.     DisposeRgn ( tempRgn );
  749.  
  750.     copyOfWindowStrucRgn = NewRgn();
  751.     GetWindowStructureRgn ( aWindow, copyOfWindowStrucRgn );
  752.  
  753.     DeviceLoop(copyOfWindowStrucRgn,CallCalcWindowAreaOnDevice,(long) &deviceLoopData,singleDevices);    
  754.  
  755.     DisposeRgn(copyOfWindowStrucRgn);
  756.     
  757.     *theBestDevice = deviceLoopData.fScreenWithLargestPartOfWindow;
  758.     *theBestScreenRect = (**(deviceLoopData.fScreenWithLargestPartOfWindow)).gdRect;
  759.  
  760.     //    Leave some space around the edges of the screen so window look good, AND
  761.     //    if the best device is the main screen, leave space for the Menubar
  762.     
  763.     InsetRect(theBestScreenRect,kScreenEdgeSlop,kScreenEdgeSlop);
  764.     if (GetMainDevice() == deviceLoopData.fScreenWithLargestPartOfWindow)
  765.         theBestScreenRect->top += GetMBarHeight();
  766.     }
  767.  
  768.  
  769.  
  770. ////////////////////////////////////////////////////////////////////////
  771. //
  772. //    Utility functions
  773. //
  774.  
  775. TWindow *
  776. GetWindowObject(WindowRef aWindow)
  777.     {
  778.     short    wKind;
  779.     
  780.     if (aWindow != nil)
  781.         {
  782.         wKind = GetWindowKind ( aWindow );
  783.  
  784.         if (wKind >= userKind)
  785.             {
  786.             //    All windowKinds >= userKind are based upon TWindow
  787.  
  788.             return (TWindow *) GetWRefCon(aWindow);
  789.             }
  790.         }
  791.     return (TWindow *) nil;
  792.     }
  793.  
  794.  
  795.  
  796.  
  797. /* static */ WindowRef
  798. TWindow::GetNewWindow(short windowID, void *wStorage, WindowRef behind)
  799.     {
  800.     if (gHasColorQuickdraw)
  801.         return GetNewCWindow(windowID,wStorage,behind);
  802.     else
  803.         return GetNewWindow(windowID,wStorage,behind);
  804.     }
  805.  
  806.  
  807. /* static */ WindowRef
  808. TWindow::NewWindow(void *wStorage, const Rect *boundsRect, ConstStr255Param title, Boolean visible, short theProc, WindowRef behind, Boolean goAwayFlag, long refCon)
  809.     {
  810.     if (gHasColorQuickdraw)
  811.         return NewCWindow(wStorage,boundsRect,title,visible,theProc,behind,goAwayFlag,refCon);
  812.     else
  813.         return NewWindow(wStorage,boundsRect,title,visible,theProc,behind,goAwayFlag,refCon);
  814.     }
  815.  
  816.  
  817. /* static */  void
  818. TWindow::DrawGrowIcon(WindowRef aWindow)
  819.     {
  820.     TGraphicsContext    graphicsContext((GrafPtr) aWindow);
  821.     Rect                growBoxRect;
  822.  
  823.     //    clip to just the bottom right corner of the window
  824.  
  825.     growBoxRect = GetWindowPort(aWindow)->portRect;
  826.     growBoxRect.top    = growBoxRect.bottom - kScrollbarWidth + 1;
  827.     growBoxRect.left= growBoxRect.right - kScrollbarWidth + 1;
  828.     ClipRect(&growBoxRect);
  829.  
  830.     ::DrawGrowIcon(aWindow);
  831.     }
  832.     
  833.  
  834. ///////////////////////////////////////////////////////////////////////////
  835. //
  836. //    WindowList functions
  837. //
  838.  
  839.  
  840. /* static */ WindowRef
  841. TWindow::FrontNonFloatingWindow()
  842.     {
  843.     WindowRef    aWindow = LMGetWindowList();
  844.     
  845.     //    Loop through window list until we find a modal or normal window,
  846.     //    while skipping over invisible and/or floating windows
  847.  
  848.     while (aWindow != NULL)
  849.         {
  850.         if (IsWindowVisible(aWindow))
  851.             {
  852.             if (GetWindowKind(aWindow) != kFloatingWindow)
  853.                 break;
  854.             }
  855.  
  856.         aWindow = GetNextWindow(aWindow);
  857.         }
  858.         
  859.     return aWindow;
  860.     }
  861.  
  862.  
  863. /* static */ WindowRef
  864. TWindow::FrontModalWindow()
  865.     {
  866.     WindowRef    aWindow = LMGetWindowList();
  867.  
  868.     //    Loop through visible windows until we find a visible modal window
  869.     //    or we get to another kind of window
  870.  
  871.     while ((aWindow != NULL) && (GetWindowKind(aWindow) == kModalWindow))
  872.         {
  873.         if (IsWindowVisible(aWindow))
  874.             return aWindow;
  875.  
  876.         aWindow = GetNextWindow ( aWindow );
  877.         }
  878.  
  879.     return NULL;
  880.     }
  881.  
  882.  
  883. /* static */ WindowRef
  884. TWindow::LastModalWindow()
  885.     {
  886.     WindowRef    aWindow        = LMGetWindowList();
  887.     WindowRef    lastModal    = (WindowRef) kNoModalWindows;
  888.     SInt16        wKind;
  889.     
  890.     while ((aWindow != NULL) && ((wKind = GetWindowKind(aWindow)) == kModalWindow))
  891.         {
  892.         if (IsWindowVisible(aWindow) && (wKind == kModalWindow))
  893.             lastModal = aWindow;
  894.  
  895.         aWindow = GetNextWindow(aWindow);
  896.         }
  897.  
  898.     return lastModal;
  899.     }
  900.  
  901.  
  902. /* static */ WindowRef
  903. TWindow::FrontFloatingWindow()
  904.     {
  905.     WindowRef    aWindow = LMGetWindowList();
  906.     SInt16        wKind;
  907.  
  908.     //    Loop through visible windows until we find a visible floating window
  909.     //    or we get to another kind of window
  910.  
  911.     while ((aWindow != NULL) && ((wKind = GetWindowKind(aWindow)) <= kFloatingWindow))
  912.         {
  913.         if (IsWindowVisible(aWindow) && (wKind == kFloatingWindow))
  914.             return aWindow;
  915.  
  916.         aWindow = GetNextWindow ( aWindow );
  917.         }
  918.  
  919.     return NULL;
  920.     }
  921.  
  922.  
  923. /* static */ WindowRef
  924. TWindow::LastFloatingWindow()
  925.     {
  926.     WindowRef    aWindow        = LMGetWindowList();
  927.     WindowRef    lastFloater = (WindowRef) kNoFloatingWindows;
  928.     SInt16        wKind;
  929.     
  930.     while ((aWindow != NULL) && ((wKind = GetWindowKind(aWindow)) <= kFloatingWindow))
  931.         {
  932.         if (IsWindowVisible(aWindow) && (wKind == kFloatingWindow))
  933.             lastFloater = aWindow;
  934.  
  935.         aWindow = GetNextWindow(aWindow);
  936.         }
  937.  
  938.     return lastFloater;
  939.     }
  940.  
  941.  
  942. /* static */ WindowRef
  943. TWindow::FrontNormalWindow()
  944.     {
  945.     WindowRef    aWindow = LMGetWindowList();
  946.     SInt16        wKind;
  947.  
  948.     //    Loop through visible windows until we find a visible floating window
  949.     //    or we get to another kind of window
  950.  
  951.     while ((aWindow != NULL) && ((wKind = GetWindowKind(aWindow)) <= kNormalWindow))
  952.         {
  953.         if (IsWindowVisible(aWindow) && (wKind == kNormalWindow))
  954.             return aWindow;
  955.  
  956.         aWindow = GetNextWindow ( aWindow );
  957.         }
  958.  
  959.     return NULL;
  960.     }
  961.  
  962.  
  963.  
  964. /* static */ void
  965. TWindow::HiliteAndActivateWindow(WindowRef aWindow,Boolean active)
  966.     {
  967.     GrafPtr        oldPort;
  968.     TWindow    *    wobj = GetWindowObject(aWindow);
  969.     
  970.     if (aWindow)
  971.         {
  972.         ::HiliteWindow(aWindow,active);
  973.  
  974.         if (wobj != nil)
  975.             {
  976.             GetPort(&oldPort);
  977.             SetPortWindowPort ( aWindow );
  978.             wobj->Activate(active);
  979.             SetPort(oldPort);
  980.             }    
  981.         }
  982.     }
  983.  
  984.  
  985. /* static */ void
  986. TWindow::SuspendResumeWindows(Boolean resuming)
  987.     {
  988.     //    When we suspend/resume, hide/show all the visible floaters
  989.     
  990.     HiliteShowHideFloatingWindows(resuming,true);
  991.     }
  992.  
  993.  
  994. /* static */ void
  995. TWindow::EnterModalState()
  996.     {
  997.     //    When we display a modal dialog, we need to unhighlight
  998.     //    all visible floaters. We also need to re-hilite them
  999.     //    afterwards.
  1000.  
  1001.     if (fgModalState++ == 0)
  1002.         HiliteShowHideFloatingWindows(false,false);
  1003.  
  1004.     TMenuBar::EnterModalState();
  1005.     }
  1006.  
  1007.  
  1008. /* static */ void
  1009. TWindow::ExitModalState()
  1010.     {
  1011.     //    When we display a modal dialog, we need to unhighlight
  1012.     //    all visible floaters. We also need to re-hilite them
  1013.     //    afterwards.
  1014.  
  1015.     if (--fgModalState == 0)    
  1016.         HiliteShowHideFloatingWindows(true,false);
  1017.  
  1018.     TMenuBar::ExitModalState();
  1019.     }
  1020.  
  1021.  
  1022. void
  1023. HiliteShowHideFloatingWindows(Boolean hiliting,Boolean dohiding)
  1024.     {
  1025.     WindowRef    aWindow;
  1026.     TWindow *    wobj;
  1027.     
  1028.     TWindow::HiliteAndActivateWindow(TWindow::FrontNonFloatingWindow(),hiliting);
  1029.  
  1030.     aWindow = LMGetWindowList();
  1031.     while ( aWindow != nil && GetWindowKind ( aWindow ) == TWindow::kFloatingWindow )
  1032.         {
  1033.         wobj = GetWindowObject ( aWindow );
  1034.         
  1035.         //    If we are hiding or showing, only hide/show windows
  1036.         //    that were visible to begin with.
  1037.         
  1038.         //    NOTE:    We use our copy of the visible flag so we can
  1039.         //            automatically show floaters on a resume event.
  1040.         
  1041.         //    NOTE:    Since this isn’t a method of TWindow, we don’t
  1042.         //            really need the “::” on ShowHide, but as long
  1043.         //            as we’re trying to avoid ambiguity.
  1044.         
  1045.         if (dohiding && (wobj != nil) && (wobj->IsVisible()))
  1046.             ::ShowHide(aWindow,hiliting);
  1047.             
  1048.         //    All floaters are hilited if any floater is hilited
  1049.  
  1050.         HiliteWindow( aWindow,hiliting);
  1051.         aWindow = GetNextWindow ( aWindow );
  1052.         }
  1053.     }
  1054.  
  1055.  
  1056. ///////////////////////////////////////////////////////////////////////////
  1057. //
  1058. //    Routines used for dealing with windows and multiple screens
  1059. //
  1060.  
  1061. pascal void
  1062. CalculateWindowAreaOnDevice(short /* depth */,short /* deviceFlags */,GDHandle targetDevice,long userData)
  1063.     {
  1064.     CalcWindowAreaDeviceLoopUserData *    deviceLoopDataPtr;
  1065.     long                                windowAreaOnThisScreen;
  1066.     Rect                                windowRectOnThisScreen;
  1067.     
  1068.     deviceLoopDataPtr = (CalcWindowAreaDeviceLoopUserData *) userData;
  1069.  
  1070.     SectRect(&deviceLoopDataPtr->fWindowBounds, &(**targetDevice).gdRect,&windowRectOnThisScreen);
  1071.     OffsetRect(&windowRectOnThisScreen,-windowRectOnThisScreen.left,-windowRectOnThisScreen.top);
  1072.     windowAreaOnThisScreen = windowRectOnThisScreen.right * windowRectOnThisScreen.bottom;
  1073.  
  1074.     if (windowAreaOnThisScreen > deviceLoopDataPtr->fLargestArea)
  1075.         {
  1076.         deviceLoopDataPtr->fLargestArea = windowAreaOnThisScreen;
  1077.         deviceLoopDataPtr->fScreenWithLargestPartOfWindow = targetDevice;
  1078.         }
  1079.     }
  1080.  
  1081.